using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace LS.GameKit
{
    [RequireComponent(typeof(CommandReceiver))]
    public abstract class CommandHandler : GameEventBehaviour
    {
        [SerializeField]
        private CommandChannel m_Channel;
        
        [SerializeField]
        private string m_Key;
        
        [SerializeField]
        private bool m_OneShot;
        
        [SerializeField]
        private float m_CoolDown = 0;
        
        [SerializeField]
        private float m_StartDelay = 0;

        protected bool isTriggered = false;
        private float startTime = 0;

        private CommandReceiver m_CommandReceiver;
        
        public CommandChannel Channel
        {
            get { return m_Channel; }
            set
            {
                if(Application.isPlaying)
                    m_CommandReceiver?.Remove(this);
                
                m_Channel = value;
                
                if(Application.isPlaying)
                    m_CommandReceiver?.Register(this);
            }
        }

        public string Key
        {
            get
            {
                return m_Key;
            }

            set
            {
                if(Application.isPlaying)
                    m_CommandReceiver?.Remove(this);
                
                m_Key = value;
                
                if(Application.isPlaying)
                    m_CommandReceiver?.Register(this);
                
            }
        }

        public bool OneShot
        {
            get
            {
                return m_OneShot;
            }
            set
            {
                m_OneShot = value;
            }
        }

        public float CoolDown
        {
            get
            {
                return m_CoolDown;
            }
            set
            {
                m_CoolDown = value;
            }
        }
        
        public float StartDelay
        {
            get
            {
                return m_StartDelay;
            }
            set
            {
                m_StartDelay = value;
            }
        }
        
        protected override void Awake()
        {
            m_CommandReceiver = GetComponent<CommandReceiver>();
            m_CommandReceiver.Register(this);
        }
        
        public virtual void OnCommand(CommandType type, params object[] args)
        {
            if (OneShot && isTriggered) return;
            
            isTriggered = true;
            
            if(CoolDown > 0)
            {
                if(Time.time > startTime + CoolDown)
                {
                    startTime = Time.time + StartDelay;
                    ExecuteCommand(type);
                }
            }
            else
            {
                ExecuteCommand(type);
            }
        }

        public abstract void PerformCommand(CommandType command, params object[] args);

        void ExecuteCommand(CommandType command, params object[] args)
        {
            if (StartDelay > 0)
                StartCoroutine(Delay(StartDelay, PerformCommand, command));
            else
                PerformCommand(command);
        }

        IEnumerator Delay(float delay, Action<CommandType, object[]> act, CommandType value, params object[] args)
        {
            float startTime = Time.time;
            yield return new WaitUntil(() => Time.time - startTime > delay);
            act?.Invoke(value, args);
        }
    }
}
